(function () {
	var VALID_KEYS = [
		'dropdownVisible',

		// XXX consider replacing these with one key that has an enum for values.
		'inSignupFlow',
		'inForgotPasswordFlow',
		'inChangePasswordFlow',
		'inMessageOnlyFlow',

		'errorMessage',
		'infoMessage',

		// dialogs with messages (info and error)
		'resetPasswordToken',
		'enrollAccountToken',
		'justVerifiedEmail',

		'configureLoginServiceDialogVisible',
		'configureLoginServiceDialogServiceName',
		'configureLoginServiceDialogSaveDisabled'
	];

	var validateKey = function (key) {
		if (!_.contains(VALID_KEYS, key)){
			throw new Error("Invalid key in loginButtonsSession: " + key);
		}
	};

	var KEY_PREFIX = "Meteor.loginButtons.";

	// XXX we should have a better pattern for code private to a package like this one
	Accounts._loginButtonsSession = {
		set: function(key, value) {
			validateKey(key);
			if (_.contains(['errorMessage', 'infoMessage'], key)){
				throw new Error("Don't set errorMessage or infoMessage directly. Instead, use errorMessage() or infoMessage().");
			}

			this._set(key, value);
		},

		_set: function(key, value) {
			Session.set(KEY_PREFIX + key, value);
		},

		get: function(key) {
			validateKey(key);
			return Session.get(KEY_PREFIX + key);
		},

		closeDropdown: function () {
			this.set('inSignupFlow', false);
			this.set('inForgotPasswordFlow', false);
			this.set('inChangePasswordFlow', false);
			this.set('inMessageOnlyFlow', false);
			this.set('dropdownVisible', false);
			this.resetMessages();
		},

		infoMessage: function(message) {
			this._set("errorMessage", null);
			this._set("infoMessage", message);
			this.ensureMessageVisible();
		},

		errorMessage: function(message) {
			this._set("errorMessage", message);
			this._set("infoMessage", null);
			this.ensureMessageVisible();
		},

		// is there a visible dialog that shows messages (info and error)
		isMessageDialogVisible: function () {
			return this.get('resetPasswordToken') ||
				this.get('enrollAccountToken') ||
				this.get('justVerifiedEmail');
		},

		// ensure that somethings displaying a message (info or error) is
		// visible.  if a dialog with messages is open, do nothing;
		// otherwise open the dropdown.
		//
		// notably this doesn't matter when only displaying a single login
		// button since then we have an explicit message dialog
		// (_loginButtonsMessageDialog), and dropdownVisible is ignored in
		// this case.
		ensureMessageVisible: function () {
			if (!this.isMessageDialogVisible()){
				this.set("dropdownVisible", true);
			}
		},

		resetMessages: function () {
			this._set("errorMessage", null);
			this._set("infoMessage", null);
		},

		configureService: function (name) {
			this.set('configureLoginServiceDialogVisible', true);
			this.set('configureLoginServiceDialogServiceName', name);
			this.set('configureLoginServiceDialogSaveDisabled', true);
			setTimeout(function(){
				$('#configure-login-service-dialog-modal').modal();
			}, 500)
		}
	};
}) ();

